package org.kalai.unifypay.util;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.security.KeyFactory;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.Signature;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.ArrayUtils;
/**
 * @description 加密解密工具类  包含常用的Base64、AES、RSA非对称加密及签名
 * @author Renne
 * @date 2016-07-22
 */
public class CipherUtils {
	//加密类型
	public static final String ENCODING = "UTF-8";
	public static final String KEY_ALGORITHM_RSA = "RSA";
	public static final String KEY_ALGORITHM_AES = "AES";
	public static final String KEY_SIGNATURE_RSA = "SHA1WithRSA";
    public static final String CIPHER_ALGORITHM_RSA = "RSA/ECB/PKCS1Padding";
    public static final String CIPHER_ALGORITHM_AES = "AES/ECB/PKCS5Padding";
    public static final int CODE_LENGTH = 2048 / 8;
    //密钥文件
	private static RSAPrivateKey privateKey = null;
	private static RSAPublicKey publicKey = null;
	private static Cipher cipher = null;
	
	//加载RSA私钥文件
	public static RSAPrivateKey generateRSAPrivateKey(){
		if(privateKey==null){
			BufferedReader br = null;
			try {
				br = new BufferedReader(new InputStreamReader(CipherUtils.class.getResourceAsStream("/alipay/rsa_private_key_2048.pem")));
				String s = br.readLine();
				String str = "";
				s = br.readLine();
				while (s.charAt(0) != '-') {
					str += s+"\r";
					s = br.readLine();
				}
				byte[] b = decryptBase64(str);
				KeyFactory kf = KeyFactory.getInstance(KEY_ALGORITHM_RSA);
				privateKey = (RSAPrivateKey) kf.generatePrivate(new PKCS8EncodedKeySpec(b));
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				try {
					br.close();
				} catch (IOException e) {
				}
			}
		}
		return privateKey;
	}
	
	//加载RSA公钥文件
	public static RSAPublicKey generateRSAPublicKey(){
		if(publicKey == null){
			BufferedReader br = null;
			try {
				br = new BufferedReader(new InputStreamReader(CipherUtils.class.getResourceAsStream("/alipay/ms_rsa_public_key_2048.pem")));
//				br = new BufferedReader(new FileReader("alipay/ms_rsa_public_key_2048.pem"));
				String s = br.readLine();
				String str = "";
				s = br.readLine();
				while (s.charAt(0) != '-') {
					str += s+"\r";
					s = br.readLine();
				}
				byte[] b = decryptBase64(str);
				KeyFactory kf = KeyFactory.getInstance(KEY_ALGORITHM_RSA);
				publicKey = (RSAPublicKey) kf.generatePublic(new X509EncodedKeySpec(b));
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				try {
					br.close();
				} catch (IOException e) {
				}
			}
		}
		return publicKey;
	}
	
	//生成AES的key
	public static SecretKeySpec generateAESKey(String encryptKey){
//		SecretKeySpec secretKeySpec = new SecretKeySpec(encryptKey.getBytes(), KEY_ALGORITHM_AES);
		return new SecretKeySpec(encryptKey.getBytes(), KEY_ALGORITHM_AES);
	}
	
	/**
	 * @description SHA1withRSA签名(私钥)
	 * @param message 待签名的内容
	 */
	public static byte[] signRSA(String message){
		byte[] data = null;
		try {
			Signature signature = Signature.getInstance(KEY_SIGNATURE_RSA);
			signature.initSign(generateRSAPrivateKey());
			signature.update(message.getBytes(ENCODING));
			data = signature.sign();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return data;
	}
	
	/**
	 * @description SHA1withRSA解签
	 * @param signature 待解签的byte[]
	 * @param message 原签名内容
	 */
	public static boolean designRSA(byte[] signature,String message){
		boolean flag = false;
		try {
			Signature sign = Signature.getInstance(KEY_SIGNATURE_RSA);
			sign.initVerify(generateRSAPublicKey());
			sign.update(message.getBytes(ENCODING));
			flag = sign.verify(signature);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return flag;	
	}
	
	/**
	 * @description RSA/ECB/PKCS1Padding加密(公钥)
	 * @param message 待加密的内容
	 * @return
	 */
	public static byte[] encryptRSA(String message){
		byte[] encrypt = null;
		try {
			cipher = Cipher.getInstance(CIPHER_ALGORITHM_RSA);  
			cipher.init(Cipher.ENCRYPT_MODE, generateRSAPublicKey()); //公钥加密 
			for (int i = 0; i < message.getBytes().length; i += CODE_LENGTH - 11) {
				byte[] temp = cipher.doFinal(ArrayUtils.subarray(message.getBytes(), i, i + CODE_LENGTH - 11));
				encrypt = ArrayUtils.addAll(encrypt, temp);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return encrypt;
	}
	
	/**
	 * @description 使用RSA/ECB/PKCS1Padding解密私钥)
	 * @param bytes 待解密的byte[]
	 */
	public static String decryptRSA(byte[] bytes){
		StringBuilder result = new StringBuilder();
		try {
			cipher = Cipher.getInstance(CIPHER_ALGORITHM_RSA);  
			cipher.init(Cipher.DECRYPT_MODE, generateRSAPrivateKey());//私钥解密  
			for (int i = 0; i < bytes.length; i += 256) {
				byte[] decrypt = cipher.doFinal(ArrayUtils.subarray(bytes, i, i + 256));
				result.append(new String(decrypt, ENCODING));
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return result.toString();
	}

	/** 
     * @description AES加密
     * @param content 待加密的内容 
     * @param encryptKey 加密密钥 
     */  
    public static byte[] encryptAES(String content, String encryptKey){  
		try {
			cipher = Cipher.getInstance(CIPHER_ALGORITHM_AES);  
			cipher.init(Cipher.ENCRYPT_MODE, generateAESKey(encryptKey));  
			return cipher.doFinal(content.getBytes(ENCODING));  
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
    }
    
    /** 
     * @description AES解密 
     * @param encryptBytes 待解密的byte[] 
     * @param decryptKey 解密密钥 
     */  
    public static String decryptAES(byte[] encryptBytes, String decryptKey){  
        try {
        	cipher = Cipher.getInstance(CIPHER_ALGORITHM_AES);  
        	cipher.init(Cipher.DECRYPT_MODE, generateAESKey(decryptKey));  
        	byte[] decryptBytes = cipher.doFinal(encryptBytes);  
        	return new String(decryptBytes, ENCODING);  
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
    }
    
    /**
     * @description Base64加密
     * @param content 待加密的内容
     */
    public static String encryptBase64(byte[] content){  
    	try {
			return new String(Base64.encodeBase64(content), ENCODING);
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
			return null;
		}
    }
    
    /**
     * @description Base64解密
     * @param content 待解密的内容
     */
    public static byte[] decryptBase64(String content){
    	return Base64.decodeBase64(content);
    }
    
    /**
     * @description MD5加密
     * @param content 待加密的内容
     */
    public static String encryptMD5(String content){
    	return DigestUtils.md5Hex(content).toUpperCase();
    }
    
    public static String getMd5Value(String sSecret) {
    	try {
    	MessageDigest bmd5 = MessageDigest.getInstance("MD5");
    	bmd5.update(sSecret.getBytes());
    	int i;
    	StringBuffer buf = new StringBuffer();
    	byte[] b = bmd5.digest();
    	for (int offset = 0; offset < b.length; offset++) {
    	i = b[offset];
    	if (i < 0)
    	i += 256;
    	if (i < 16)
    	buf.append("0");
    	buf.append(Integer.toHexString(i));
    	}
    	return buf.toString();
    	} catch (NoSuchAlgorithmException e) {
    	e.printStackTrace();
    	}
    	return "";
	}
    
	public static void main(String[] args) {
//		String message = "{\"bizcode\":\"1001\",\"bizData\":{\"authCode\":\"130141285587486081\"},\"transAmt\":\"0.01\",\"subject\":\"测试\",\"memberNo\":\"G100117097221966\"}c6fefb5abf8a2addd6185bafb8cba20e";
//		byte[] sign = signRSA(message);
//		System.out.println(designRSA(sign, "杭州卡来科技有限公司"));
		System.out.println(encryptMD5("12345"));
//		System.out.println(getMd5Value(message));
	}
}
